From df236fba581e1b14ebf86562d5869b68761f4bf5 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Wed, 17 Sep 2014 16:16:45 -0600 Subject: [PATCH] gtkwindow: Make sure to update the shadow width, opaque region and border windows when realizing Otherwise, they might not be properly set before the window is mapped. For the opaque region and border window, it means that they won't get set before the next size allocation, which tends to not be a bit deal. For the shadow width, though, _GTK_FRAME_EXTENTS has a different meaning when it's set before the window is mapped, so we need to make sure that it's properly set when the window is mapped. --- gtk/gtkwindow.c | 1385 ++++++++++++++++++++++++----------------------- 1 file changed, 700 insertions(+), 685 deletions(-) diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 5145b7427e..4a686374ec 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -6248,830 +6248,857 @@ check_scale_changed (GtkWindow *window) } static void -gtk_window_realize (GtkWidget *widget) +sum_borders (GtkBorder *one, + GtkBorder *two) { - GtkAllocation allocation; - GtkWindow *window; - GdkWindow *parent_window; - GdkWindow *gdk_window; - GdkWindowAttr attributes; - gint attributes_mask; - GtkWindowPrivate *priv; + one->top += two->top; + one->right += two->right; + one->bottom += two->bottom; + one->left += two->left; +} + +static void +max_borders (GtkBorder *one, + GtkBorder *two) +{ + one->top = MAX (one->top, two->top); + one->right = MAX (one->right, two->right); + one->bottom = MAX (one->bottom, two->bottom); + one->left = MAX (one->left, two->left); +} + +static void +subtract_borders (GtkBorder *one, + GtkBorder *two) +{ + one->top -= two->top; + one->right -= two->right; + one->bottom -= two->bottom; + one->left -= two->left; +} + +static void +add_window_frame_style_class (GtkStyleContext *context) +{ + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND); + gtk_style_context_add_class (context, "window-frame"); +} + +static void +get_shadow_width (GtkWidget *widget, + GtkBorder *shadow_width) +{ + GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv; + GtkBorder border = { 0 }; + GtkBorder d = { 0 }; + GtkBorder margin; + GtkStyleContext *context; + GtkStateFlags state, s; + GtkCssValue *shadows; gint i; - GList *link; - window = GTK_WINDOW (widget); - priv = window->priv; + *shadow_width = border; - if (!priv->client_decorated && gtk_window_should_use_csd (window)) - create_decoration (widget); + if (!priv->decorated || + !priv->client_decorated) + return; - gtk_widget_get_allocation (widget, &allocation); + if (priv->maximized || + priv->fullscreen || + priv->tiled) + return; - if (gtk_widget_get_parent_window (widget)) - { - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT); - G_GNUC_END_IGNORE_DEPRECATIONS; + state = gtk_widget_get_state_flags (widget); + context = gtk_widget_get_style_context (widget); - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.window_type = GDK_WINDOW_CHILD; + gtk_style_context_save (context); + add_window_frame_style_class (context); - attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK; + /* We don't want windows to jump as they go to backdrop, + * therefore we use the maximum of the decoration sizes + * for focused and unfocused. + */ + for (i = 0; i < 2; i++) + { + if (i == 0) + s = state & ~GTK_STATE_FLAG_BACKDROP; + else + s = state | GTK_STATE_FLAG_BACKDROP; - attributes.visual = gtk_widget_get_visual (widget); - attributes.wclass = GDK_INPUT_OUTPUT; + /* Always sum border + padding */ + gtk_style_context_get_border (context, s, &border); + gtk_style_context_get_padding (context, s, &d); + sum_borders (&d, &border); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + /* Calculate the size of the drop shadows ... */ + gtk_style_context_set_state (context, s); + shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW); + _gtk_css_shadows_value_get_extents (shadows, &border); - gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, attributes_mask); - gtk_widget_set_window (widget, gdk_window); - gtk_widget_register_window (widget, gdk_window); - gtk_widget_set_realized (widget, TRUE); + if (priv->type != GTK_WINDOW_POPUP) + { + /* ... and compare it to the margin size, which we use for resize grips */ + gtk_style_context_get_margin (context, s, &margin); + max_borders (&border, &margin); + } - return; + sum_borders (&d, &border); + max_borders (shadow_width, &d); } - G_GNUC_BEGIN_IGNORE_DEPRECATIONS; - gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE); - G_GNUC_END_IGNORE_DEPRECATIONS; + gtk_style_context_restore (context); +} - /* ensure widget tree is properly size allocated */ - if (allocation.x == -1 && - allocation.y == -1 && - allocation.width == 1 && - allocation.height == 1) - { - gint w, h; +/* We're placing 8 input-only windows around + * the window content as resize handles, as + * follows: + * + * +-----------------------------------+ + * | +------+-----------------+------+ | + * | | | | | | + * | | +--+-----------------+--+ | | + * | | | | | | + * | +---+ +---+ | + * | | | | | | + * | | | | | | + * | | | | | | + * | +---+ +---+ | + * | | | | | | + * | | +--+-----------------+--+ | | + * | | | | | | + * | +------+-----------------+------+ | + * +-----------------------------------+ + * + * The corner windows are shaped to allow them + * to extend into the edges. If the window is + * not resizable in both dimensions, we hide + * the corner windows and the edge windows in + * the nonresizable dimension and make the + * remaining edge window extend all the way. + * + * The border are where we place the resize handles + * is also used to draw the window shadow, which may + * extend out farther than the handles (or the other + * way around). + */ +static void +update_border_windows (GtkWindow *window) +{ + GtkWidget *widget = (GtkWidget *)window; + GtkWindowPrivate *priv = window->priv; + gboolean resize_h, resize_v; + gint handle; + cairo_region_t *region; + cairo_rectangle_int_t rect; + gint width, height; + GtkBorder border; + GtkBorder window_border; + GtkStyleContext *context; + GtkStateFlags state; - allocation.x = 0; - allocation.y = 0; + if (!priv->client_decorated) + return; - gtk_window_guess_default_size (window, &allocation.width, &allocation.height); - gtk_window_get_remembered_size (window, &w, &h); - allocation.width = MAX (allocation.width, w); - allocation.height = MAX (allocation.height, h); - if (allocation.width == 0 || allocation.height == 0) - { - /* non-empty window */ - allocation.width = 200; - allocation.height = 200; - } - gtk_widget_size_allocate (widget, &allocation); - - _gtk_container_queue_resize (GTK_CONTAINER (widget)); + state = gtk_widget_get_state_flags (widget); + context = gtk_widget_get_style_context (widget); - g_return_if_fail (!gtk_widget_get_realized (widget)); - } + gtk_style_context_save (context); + add_window_frame_style_class (context); + gtk_style_context_set_state (context, state); + gtk_style_context_get_margin (context, state, &border); + gtk_widget_style_get (widget, + "decoration-resize-handle", &handle, + NULL); + gtk_style_context_restore (context); + get_shadow_width (widget, &window_border); - if (priv->hardcoded_window) + if (priv->border_window[0] == NULL) + goto shape; + + if (!priv->resizable || + priv->tiled || + priv->fullscreen || + priv->maximized) { - gdk_window = priv->hardcoded_window; - gtk_widget_get_allocation (widget, &allocation); - gdk_window_resize (gdk_window, allocation.width, allocation.height); + resize_h = resize_v = FALSE; } else { - switch (priv->type) + resize_h = resize_v = TRUE; + if (priv->geometry_info) { - case GTK_WINDOW_TOPLEVEL: - attributes.window_type = GDK_WINDOW_TOPLEVEL; - break; - case GTK_WINDOW_POPUP: - attributes.window_type = GDK_WINDOW_TEMP; - break; - default: - g_warning (G_STRLOC": Unknown window type %d!", priv->type); - break; - } - -#ifdef GDK_WINDOWING_WAYLAND - if (priv->use_subsurface && - GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget))) - attributes.window_type = GDK_WINDOW_SUBSURFACE; -#endif + GdkGeometry *geometry = &priv->geometry_info->geometry; + GdkWindowHints flags = priv->geometry_info->mask; - attributes.title = priv->title; - attributes.wmclass_name = priv->wmclass_name; - attributes.wmclass_class = priv->wmclass_class; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); + if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE)) + { + resize_h = geometry->min_width != geometry->max_width; + resize_v = geometry->min_height != geometry->max_height; + } + } + } - attributes_mask = 0; - parent_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); + width = gtk_widget_get_allocated_width (widget) - (window_border.left + window_border.right); + height = gtk_widget_get_allocated_height (widget) - (window_border.top + window_border.bottom); - gtk_widget_get_allocation (widget, &allocation); - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.event_mask = gtk_widget_get_events (widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON_MOTION_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_FOCUS_CHANGE_MASK | - GDK_STRUCTURE_MASK); - - if (priv->decorated && - (priv->client_decorated || priv->custom_title)) - attributes.event_mask |= GDK_POINTER_MOTION_MASK; - - attributes.type_hint = priv->type_hint; - - attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT; - attributes_mask |= (priv->title ? GDK_WA_TITLE : 0); - attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0); - - gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask); - } - - gtk_widget_set_window (widget, gdk_window); - gtk_widget_register_window (widget, gdk_window); - gtk_widget_set_realized (widget, TRUE); - - /* We don't need to set a background on the GdkWindow; with decorations - * we draw the background ourself - */ - if (!priv->client_decorated) - gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window); + if (resize_h && resize_v) + { + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST], + window_border.left - border.left, window_border.top - border.top, + border.left + handle, border.top + handle); + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST], + window_border.left + width - handle, window_border.top - border.top, + border.right + handle, border.top + handle); + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST], + window_border.left - border.left, window_border.top + height - handle, + window_border.left + handle, border.bottom + handle); + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST], + window_border.left + width - handle, window_border.top + height - handle, + border.right + handle, border.bottom + handle); - attributes.x = allocation.x; - attributes.y = allocation.y; - attributes.width = allocation.width; - attributes.height = allocation.height; - attributes.window_type = GDK_WINDOW_CHILD; + rect.x = 0; + rect.y = 0; + rect.width = border.left + handle; + rect.height = border.top + handle; + region = cairo_region_create_rectangle (&rect); + rect.x = border.left; + rect.y = border.top; + rect.width = handle; + rect.height = handle; + cairo_region_subtract_rectangle (region, &rect); + gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST], + region, 0, 0); + cairo_region_destroy (region); - attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK; + rect.x = 0; + rect.y = 0; + rect.width = border.right + handle; + rect.height = border.top + handle; + region = cairo_region_create_rectangle (&rect); + rect.x = 0; + rect.y = border.top; + rect.width = handle; + rect.height = handle; + cairo_region_subtract_rectangle (region, &rect); + gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST], + region, 0, 0); + cairo_region_destroy (region); - attributes.visual = gtk_widget_get_visual (widget); - attributes.wclass = GDK_INPUT_OUTPUT; + rect.x = 0; + rect.y = 0; + rect.width = border.left + handle; + rect.height = border.bottom + handle; + region = cairo_region_create_rectangle (&rect); + rect.x = border.left; + rect.y = 0; + rect.width = handle; + rect.height = handle; + cairo_region_subtract_rectangle (region, &rect); + gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST], + region, 0, 0); + cairo_region_destroy (region); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + rect.x = 0; + rect.y = 0; + rect.width = border.right + handle; + rect.height = border.bottom + handle; + region = cairo_region_create_rectangle (&rect); + rect.x = 0; + rect.y = 0; + rect.width = handle; + rect.height = handle; + cairo_region_subtract_rectangle (region, &rect); + gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST], + region, 0, 0); + cairo_region_destroy (region); - if (priv->client_decorated && priv->type == GTK_WINDOW_TOPLEVEL) + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]); + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]); + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]); + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]); + } + else { - GdkCursorType cursor_type[8] = { - GDK_TOP_LEFT_CORNER, - GDK_TOP_SIDE, - GDK_TOP_RIGHT_CORNER, - GDK_LEFT_SIDE, - GDK_RIGHT_SIDE, - GDK_BOTTOM_LEFT_CORNER, - GDK_BOTTOM_SIDE, - GDK_BOTTOM_RIGHT_CORNER - }; + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]); + } - attributes.wclass = GDK_INPUT_ONLY; - attributes.width = 1; - attributes.height = 1; - attributes.event_mask = GDK_BUTTON_PRESS_MASK; - attributes_mask = GDK_WA_CURSOR; + if (resize_v) + { + gint x, w; - for (i = 0; i < 8; i++) + if (resize_h) { - attributes.cursor = gdk_cursor_new (cursor_type[i]); - priv->border_window[i] = gdk_window_new (gdk_window, &attributes, attributes_mask); - g_object_unref (attributes.cursor); - - gdk_window_show (priv->border_window[i]); - gtk_widget_register_window (widget, priv->border_window[i]); + x = window_border.left + handle; + w = width - 2 * handle; + } + else + { + x = 0; + w = width + window_border.left + window_border.right; } - } - if (priv->transient_parent && - gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent))) - gdk_window_set_transient_for (gdk_window, - gtk_widget_get_window (GTK_WIDGET (priv->transient_parent))); + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH], + x, window_border.top - border.top, + w, border.top); + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH], + x, window_border.top + height, + w, border.bottom); - if (priv->wm_role) - gdk_window_set_role (gdk_window, priv->wm_role); - - if (!priv->decorated || priv->client_decorated) - gdk_window_set_decorations (gdk_window, 0); - else if (priv->custom_title) - gdk_window_set_decorations (gdk_window, GDK_DECOR_BORDER); - - if (!priv->deletable) - gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE); - - if (gtk_window_get_skip_pager_hint (window)) - gdk_window_set_skip_pager_hint (gdk_window, TRUE); - - if (gtk_window_get_skip_taskbar_hint (window)) - gdk_window_set_skip_taskbar_hint (gdk_window, TRUE); - - if (gtk_window_get_accept_focus (window)) - gdk_window_set_accept_focus (gdk_window, TRUE); - else - gdk_window_set_accept_focus (gdk_window, FALSE); - - if (gtk_window_get_focus_on_map (window)) - gdk_window_set_focus_on_map (gdk_window, TRUE); - else - gdk_window_set_focus_on_map (gdk_window, FALSE); - - if (priv->modal) - gdk_window_set_modal_hint (gdk_window, TRUE); + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH]); + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH]); + } else - gdk_window_set_modal_hint (gdk_window, FALSE); - - if (priv->startup_id) { -#ifdef GDK_WINDOWING_X11 - if (GDK_IS_X11_WINDOW (gdk_window)) - { - guint32 timestamp = extract_time_from_startup_id (priv->startup_id); - if (timestamp != GDK_CURRENT_TIME) - gdk_x11_window_set_user_time (gdk_window, timestamp); - } -#endif - if (!startup_id_is_fake (priv->startup_id)) - gdk_window_set_startup_id (gdk_window, priv->startup_id); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH]); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH]); } -#ifdef GDK_WINDOWING_X11 - if (priv->initial_timestamp != GDK_CURRENT_TIME) + if (resize_h) { - if (GDK_IS_X11_WINDOW (gdk_window)) - gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp); - } -#endif + gint y, h; - if (priv->application) - gtk_application_handle_window_realize (priv->application, window); + if (resize_v) + { + y = window_border.top + handle; + h = height - 2 * handle; + } + else + { + y = 0; + h = height + window_border.top + window_border.bottom; + } - /* Icons */ - gtk_window_realize_icon (window); + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST], + window_border.left - border.left, y, + border.left, h); - link = priv->popovers; + gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST], + window_border.left + width, y, + border.right, h); - while (link) + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_WEST]); + gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_EAST]); + } + else { - GtkWindowPopover *popover = link->data; - link = link->next; - popover_realize (popover->widget, popover, window); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_WEST]); + gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_EAST]); } - check_scale_changed (window); -} +shape: + /* we also update the input shape, which makes it so that clicks + * outside the border windows go through + */ -static void -popover_unrealize (GtkWidget *widget, - GtkWindowPopover *popover, - GtkWindow *window) -{ - gtk_widget_unregister_window (GTK_WIDGET (window), popover->window); - gtk_widget_unrealize (popover->widget); - gdk_window_destroy (popover->window); - popover->window = NULL; + if (priv->type != GTK_WINDOW_POPUP) + subtract_borders (&window_border, &border); + + rect.x = window_border.left; + rect.y = window_border.top; + rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right; + rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom; + region = cairo_region_create_rectangle (&rect); + gtk_widget_input_shape_combine_region (widget, region); + cairo_region_destroy (region); } static void -gtk_window_unrealize (GtkWidget *widget) +update_shadow_width (GtkWindow *window, + GtkBorder *border) { - GtkWindow *window = GTK_WINDOW (widget); - GtkWindowPrivate *priv = window->priv; - GtkWindowGeometryInfo *info; - GList *link; - gint i; - - /* On unrealize, we reset the size of the window such - * that we will re-apply the default sizing stuff - * next time we show the window. - * - * Default positioning is reset on unmap, instead of unrealize. - */ - priv->need_default_size = TRUE; - info = gtk_window_get_geometry_info (window, FALSE); - if (info) - { - info->resize_width = -1; - info->resize_height = -1; - info->last.configure_request.x = 0; - info->last.configure_request.y = 0; - info->last.configure_request.width = -1; - info->last.configure_request.height = -1; - /* be sure we reset geom hints on re-realize */ - info->last.flags = 0; - } - - if (priv->popup_menu) - { - gtk_widget_destroy (priv->popup_menu); - priv->popup_menu = NULL; - } - - /* Icons */ - gtk_window_unrealize_icon (window); - - if (priv->border_window[0] != NULL) - { - for (i = 0; i < 8; i++) - { - gtk_widget_unregister_window (widget, priv->border_window[i]); - gdk_window_destroy (priv->border_window[i]); - priv->border_window[i] = NULL; - } - } - - link = priv->popovers; - - while (link) - { - GtkWindowPopover *popover = link->data; - link = link->next; - popover_unrealize (popover->widget, popover, window); - } + GdkWindow *gdk_window; - GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget); + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); - priv->hardcoded_window = NULL; + if (gdk_window) + gdk_window_set_shadow_width (gdk_window, + border->left, + border->right, + border->top, + border->bottom); } static void -sum_borders (GtkBorder *one, - GtkBorder *two) +corner_rect (cairo_rectangle_int_t *rect, + const GtkCssValue *value) { - one->top += two->top; - one->right += two->right; - one->bottom += two->bottom; - one->left += two->left; + rect->width = _gtk_css_corner_value_get_x (value, 100); + rect->height = _gtk_css_corner_value_get_y (value, 100); } static void -max_borders (GtkBorder *one, - GtkBorder *two) +subtract_corners_from_region (cairo_region_t *region, + cairo_rectangle_int_t *extents, + GtkStyleContext *context) { - one->top = MAX (one->top, two->top); - one->right = MAX (one->right, two->right); - one->bottom = MAX (one->bottom, two->bottom); - one->left = MAX (one->left, two->left); -} + cairo_rectangle_int_t rect; -static void -subtract_borders (GtkBorder *one, - GtkBorder *two) -{ - one->top -= two->top; - one->right -= two->right; - one->bottom -= two->bottom; - one->left -= two->left; + gtk_style_context_save (context); + add_window_frame_style_class (context); + + corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS)); + rect.x = extents->x; + rect.y = extents->y; + cairo_region_subtract_rectangle (region, &rect); + + corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS)); + rect.x = extents->x + extents->width - rect.width; + rect.y = extents->y; + cairo_region_subtract_rectangle (region, &rect); + + corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS)); + rect.x = extents->x; + rect.y = extents->y + extents->height - rect.height; + cairo_region_subtract_rectangle (region, &rect); + + corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)); + rect.x = extents->x + extents->width - rect.width; + rect.y = extents->y + extents->height - rect.height; + cairo_region_subtract_rectangle (region, &rect); + + gtk_style_context_restore (context); } static void -add_window_frame_style_class (GtkStyleContext *context) +update_opaque_region (GtkWindow *window, + GtkBorder *border, + const GtkAllocation *allocation) { - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_BACKGROUND); - gtk_style_context_add_class (context, "window-frame"); + GtkWidget *widget = GTK_WIDGET (window); + cairo_region_t *opaque_region; + GtkStyleContext *context; + gboolean is_opaque = FALSE; + + if (!gtk_widget_get_realized (widget)) + return; + + context = gtk_widget_get_style_context (widget); + + if (!gtk_widget_get_app_paintable (widget)) + { + const GdkRGBA *color; + color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); + is_opaque = (color->alpha >= 1.0); + } + + if (is_opaque) + { + cairo_rectangle_int_t rect; + + rect.x = border->left; + rect.y = border->top; + rect.width = allocation->width - border->left - border->right; + rect.height = allocation->height - border->top - border->bottom; + + opaque_region = cairo_region_create_rectangle (&rect); + + subtract_corners_from_region (opaque_region, &rect, context); + } + else + { + opaque_region = NULL; + } + + gdk_window_set_opaque_region (gtk_widget_get_window (widget), opaque_region); + + cairo_region_destroy (opaque_region); } static void -update_window_style_classes (GtkWindow *window) +update_realized_window_properties (GtkWindow *window, + GtkAllocation *child_allocation, + GtkBorder *window_border) { GtkWindowPrivate *priv = window->priv; - GtkStyleContext *context; - context = gtk_widget_get_style_context (GTK_WIDGET (window)); + if (priv->client_decorated) + update_shadow_width (window, window_border); - if (priv->tiled) - gtk_style_context_add_class (context, "tiled"); - else - gtk_style_context_remove_class (context, "tiled"); + update_opaque_region (window, window_border, child_allocation); - if (priv->maximized) - gtk_style_context_add_class (context, "maximized"); - else - gtk_style_context_remove_class (context, "maximized"); + if (gtk_widget_is_toplevel (GTK_WIDGET (window))) + update_border_windows (window); } static void -get_shadow_width (GtkWidget *widget, - GtkBorder *shadow_width) +gtk_window_realize (GtkWidget *widget) { - GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv; - GtkBorder border = { 0 }; - GtkBorder d = { 0 }; - GtkBorder margin; - GtkStyleContext *context; - GtkStateFlags state, s; - GtkCssValue *shadows; + GtkAllocation allocation; + GtkAllocation child_allocation; + GtkWindow *window; + GdkWindow *parent_window; + GdkWindow *gdk_window; + GdkWindowAttr attributes; + GtkBorder window_border; + gint attributes_mask; + GtkWindowPrivate *priv; gint i; + GList *link; - *shadow_width = border; + window = GTK_WINDOW (widget); + priv = window->priv; - if (!priv->decorated || - !priv->client_decorated) - return; + if (!priv->client_decorated && gtk_window_should_use_csd (window)) + create_decoration (widget); - if (priv->maximized || - priv->fullscreen || - priv->tiled) - return; + gtk_widget_get_allocation (widget, &allocation); - state = gtk_widget_get_state_flags (widget); - context = gtk_widget_get_style_context (widget); + if (gtk_widget_get_parent_window (widget)) + { + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gtk_container_set_resize_mode (GTK_CONTAINER (widget), GTK_RESIZE_PARENT); + G_GNUC_END_IGNORE_DEPRECATIONS; - gtk_style_context_save (context); - add_window_frame_style_class (context); + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; - /* We don't want windows to jump as they go to backdrop, - * therefore we use the maximum of the decoration sizes - * for focused and unfocused. - */ - for (i = 0; i < 2; i++) - { - if (i == 0) - s = state & ~GTK_STATE_FLAG_BACKDROP; - else - s = state | GTK_STATE_FLAG_BACKDROP; + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK; - /* Always sum border + padding */ - gtk_style_context_get_border (context, s, &border); - gtk_style_context_get_padding (context, s, &d); - sum_borders (&d, &border); + attributes.visual = gtk_widget_get_visual (widget); + attributes.wclass = GDK_INPUT_OUTPUT; - /* Calculate the size of the drop shadows ... */ - gtk_style_context_set_state (context, s); - shadows = _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BOX_SHADOW); - _gtk_css_shadows_value_get_extents (shadows, &border); + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; - if (priv->type != GTK_WINDOW_POPUP) - { - /* ... and compare it to the margin size, which we use for resize grips */ - gtk_style_context_get_margin (context, s, &margin); - max_borders (&border, &margin); - } + gdk_window = gdk_window_new (gtk_widget_get_parent_window (widget), + &attributes, attributes_mask); + gtk_widget_set_window (widget, gdk_window); + gtk_widget_register_window (widget, gdk_window); + gtk_widget_set_realized (widget, TRUE); - sum_borders (&d, &border); - max_borders (shadow_width, &d); + return; } - gtk_style_context_restore (context); -} + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + gtk_container_set_resize_mode (GTK_CONTAINER (window), GTK_RESIZE_QUEUE); + G_GNUC_END_IGNORE_DEPRECATIONS; -/* We're placing 8 input-only windows around - * the window content as resize handles, as - * follows: - * - * +-----------------------------------+ - * | +------+-----------------+------+ | - * | | | | | | - * | | +--+-----------------+--+ | | - * | | | | | | - * | +---+ +---+ | - * | | | | | | - * | | | | | | - * | | | | | | - * | +---+ +---+ | - * | | | | | | - * | | +--+-----------------+--+ | | - * | | | | | | - * | +------+-----------------+------+ | - * +-----------------------------------+ - * - * The corner windows are shaped to allow them - * to extend into the edges. If the window is - * not resizable in both dimensions, we hide - * the corner windows and the edge windows in - * the nonresizable dimension and make the - * remaining edge window extend all the way. - * - * The border are where we place the resize handles - * is also used to draw the window shadow, which may - * extend out farther than the handles (or the other - * way around). - */ -static void -update_border_windows (GtkWindow *window) -{ - GtkWidget *widget = (GtkWidget *)window; - GtkWindowPrivate *priv = window->priv; - gboolean resize_h, resize_v; - gint handle; - cairo_region_t *region; - cairo_rectangle_int_t rect; - gint width, height; - GtkBorder border; - GtkBorder window_border; - GtkStyleContext *context; - GtkStateFlags state; + /* ensure widget tree is properly size allocated */ + if (allocation.x == -1 && + allocation.y == -1 && + allocation.width == 1 && + allocation.height == 1) + { + gint w, h; - if (!priv->client_decorated) - return; + allocation.x = 0; + allocation.y = 0; - state = gtk_widget_get_state_flags (widget); - context = gtk_widget_get_style_context (widget); + gtk_window_guess_default_size (window, &allocation.width, &allocation.height); + gtk_window_get_remembered_size (window, &w, &h); + allocation.width = MAX (allocation.width, w); + allocation.height = MAX (allocation.height, h); + if (allocation.width == 0 || allocation.height == 0) + { + /* non-empty window */ + allocation.width = 200; + allocation.height = 200; + } + gtk_widget_size_allocate (widget, &allocation); - gtk_style_context_save (context); - add_window_frame_style_class (context); - gtk_style_context_set_state (context, state); - gtk_style_context_get_margin (context, state, &border); - gtk_widget_style_get (widget, - "decoration-resize-handle", &handle, - NULL); - gtk_style_context_restore (context); - get_shadow_width (widget, &window_border); + _gtk_container_queue_resize (GTK_CONTAINER (widget)); - if (priv->border_window[0] == NULL) - goto shape; + g_return_if_fail (!gtk_widget_get_realized (widget)); + } - if (!priv->resizable || - priv->tiled || - priv->fullscreen || - priv->maximized) + if (priv->hardcoded_window) { - resize_h = resize_v = FALSE; + gdk_window = priv->hardcoded_window; + gtk_widget_get_allocation (widget, &allocation); + gdk_window_resize (gdk_window, allocation.width, allocation.height); } else { - resize_h = resize_v = TRUE; - if (priv->geometry_info) + switch (priv->type) { - GdkGeometry *geometry = &priv->geometry_info->geometry; - GdkWindowHints flags = priv->geometry_info->mask; - - if ((flags & GDK_HINT_MIN_SIZE) && (flags & GDK_HINT_MAX_SIZE)) - { - resize_h = geometry->min_width != geometry->max_width; - resize_v = geometry->min_height != geometry->max_height; - } + case GTK_WINDOW_TOPLEVEL: + attributes.window_type = GDK_WINDOW_TOPLEVEL; + break; + case GTK_WINDOW_POPUP: + attributes.window_type = GDK_WINDOW_TEMP; + break; + default: + g_warning (G_STRLOC": Unknown window type %d!", priv->type); + break; } - } - width = gtk_widget_get_allocated_width (widget) - (window_border.left + window_border.right); - height = gtk_widget_get_allocated_height (widget) - (window_border.top + window_border.bottom); +#ifdef GDK_WINDOWING_WAYLAND + if (priv->use_subsurface && + GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (widget))) + attributes.window_type = GDK_WINDOW_SUBSURFACE; +#endif - if (resize_h && resize_v) - { - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST], - window_border.left - border.left, window_border.top - border.top, - border.left + handle, border.top + handle); - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST], - window_border.left + width - handle, window_border.top - border.top, - border.right + handle, border.top + handle); - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST], - window_border.left - border.left, window_border.top + height - handle, - window_border.left + handle, border.bottom + handle); - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST], - window_border.left + width - handle, window_border.top + height - handle, - border.right + handle, border.bottom + handle); + attributes.title = priv->title; + attributes.wmclass_name = priv->wmclass_name; + attributes.wmclass_class = priv->wmclass_class; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.visual = gtk_widget_get_visual (widget); - rect.x = 0; - rect.y = 0; - rect.width = border.left + handle; - rect.height = border.top + handle; - region = cairo_region_create_rectangle (&rect); - rect.x = border.left; - rect.y = border.top; - rect.width = handle; - rect.height = handle; - cairo_region_subtract_rectangle (region, &rect); - gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST], - region, 0, 0); - cairo_region_destroy (region); + attributes_mask = 0; + parent_window = gdk_screen_get_root_window (gtk_widget_get_screen (widget)); - rect.x = 0; - rect.y = 0; - rect.width = border.right + handle; - rect.height = border.top + handle; - region = cairo_region_create_rectangle (&rect); - rect.x = 0; - rect.y = border.top; - rect.width = handle; - rect.height = handle; - cairo_region_subtract_rectangle (region, &rect); - gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST], - region, 0, 0); - cairo_region_destroy (region); + gtk_widget_get_allocation (widget, &allocation); + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.event_mask = gtk_widget_get_events (widget); + attributes.event_mask |= (GDK_EXPOSURE_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_FOCUS_CHANGE_MASK | + GDK_STRUCTURE_MASK); - rect.x = 0; - rect.y = 0; - rect.width = border.left + handle; - rect.height = border.bottom + handle; - region = cairo_region_create_rectangle (&rect); - rect.x = border.left; - rect.y = 0; - rect.width = handle; - rect.height = handle; - cairo_region_subtract_rectangle (region, &rect); - gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST], - region, 0, 0); - cairo_region_destroy (region); + if (priv->decorated && + (priv->client_decorated || priv->custom_title)) + attributes.event_mask |= GDK_POINTER_MOTION_MASK; - rect.x = 0; - rect.y = 0; - rect.width = border.right + handle; - rect.height = border.bottom + handle; - region = cairo_region_create_rectangle (&rect); - rect.x = 0; - rect.y = 0; - rect.width = handle; - rect.height = handle; - cairo_region_subtract_rectangle (region, &rect); - gdk_window_shape_combine_region (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST], - region, 0, 0); - cairo_region_destroy (region); + attributes.type_hint = priv->type_hint; - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]); - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]); - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]); - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]); - } - else - { - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_WEST]); - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH_EAST]); - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_WEST]); - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH_EAST]); + attributes_mask |= GDK_WA_VISUAL | GDK_WA_TYPE_HINT; + attributes_mask |= (priv->title ? GDK_WA_TITLE : 0); + attributes_mask |= (priv->wmclass_name ? GDK_WA_WMCLASS : 0); + + gdk_window = gdk_window_new (parent_window, &attributes, attributes_mask); } - if (resize_v) + gtk_widget_set_window (widget, gdk_window); + gtk_widget_register_window (widget, gdk_window); + gtk_widget_set_realized (widget, TRUE); + + /* We don't need to set a background on the GdkWindow; with decorations + * we draw the background ourself + */ + if (!priv->client_decorated) + gtk_style_context_set_background (gtk_widget_get_style_context (widget), gdk_window); + + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + attributes.window_type = GDK_WINDOW_CHILD; + + attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK; + + attributes.visual = gtk_widget_get_visual (widget); + attributes.wclass = GDK_INPUT_OUTPUT; + + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; + + if (priv->client_decorated && priv->type == GTK_WINDOW_TOPLEVEL) { - gint x, w; + GdkCursorType cursor_type[8] = { + GDK_TOP_LEFT_CORNER, + GDK_TOP_SIDE, + GDK_TOP_RIGHT_CORNER, + GDK_LEFT_SIDE, + GDK_RIGHT_SIDE, + GDK_BOTTOM_LEFT_CORNER, + GDK_BOTTOM_SIDE, + GDK_BOTTOM_RIGHT_CORNER + }; - if (resize_h) - { - x = window_border.left + handle; - w = width - 2 * handle; - } - else + attributes.wclass = GDK_INPUT_ONLY; + attributes.width = 1; + attributes.height = 1; + attributes.event_mask = GDK_BUTTON_PRESS_MASK; + attributes_mask = GDK_WA_CURSOR; + + for (i = 0; i < 8; i++) { - x = 0; - w = width + window_border.left + window_border.right; + attributes.cursor = gdk_cursor_new (cursor_type[i]); + priv->border_window[i] = gdk_window_new (gdk_window, &attributes, attributes_mask); + g_object_unref (attributes.cursor); + + gdk_window_show (priv->border_window[i]); + gtk_widget_register_window (widget, priv->border_window[i]); } + } + + if (priv->transient_parent && + gtk_widget_get_realized (GTK_WIDGET (priv->transient_parent))) + gdk_window_set_transient_for (gdk_window, + gtk_widget_get_window (GTK_WIDGET (priv->transient_parent))); + + if (priv->wm_role) + gdk_window_set_role (gdk_window, priv->wm_role); + + if (!priv->decorated || priv->client_decorated) + gdk_window_set_decorations (gdk_window, 0); + else if (priv->custom_title) + gdk_window_set_decorations (gdk_window, GDK_DECOR_BORDER); + + if (!priv->deletable) + gdk_window_set_functions (gdk_window, GDK_FUNC_ALL | GDK_FUNC_CLOSE); + + if (gtk_window_get_skip_pager_hint (window)) + gdk_window_set_skip_pager_hint (gdk_window, TRUE); + + if (gtk_window_get_skip_taskbar_hint (window)) + gdk_window_set_skip_taskbar_hint (gdk_window, TRUE); - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_NORTH], - x, window_border.top - border.top, - w, border.top); - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_SOUTH], - x, window_border.top + height, - w, border.bottom); + if (gtk_window_get_accept_focus (window)) + gdk_window_set_accept_focus (gdk_window, TRUE); + else + gdk_window_set_accept_focus (gdk_window, FALSE); - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_NORTH]); - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_SOUTH]); - } + if (gtk_window_get_focus_on_map (window)) + gdk_window_set_focus_on_map (gdk_window, TRUE); else - { - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_NORTH]); - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_SOUTH]); - } + gdk_window_set_focus_on_map (gdk_window, FALSE); - if (resize_h) - { - gint y, h; + if (priv->modal) + gdk_window_set_modal_hint (gdk_window, TRUE); + else + gdk_window_set_modal_hint (gdk_window, FALSE); - if (resize_v) - { - y = window_border.top + handle; - h = height - 2 * handle; - } - else + if (priv->startup_id) + { +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_WINDOW (gdk_window)) { - y = 0; - h = height + window_border.top + window_border.bottom; + guint32 timestamp = extract_time_from_startup_id (priv->startup_id); + if (timestamp != GDK_CURRENT_TIME) + gdk_x11_window_set_user_time (gdk_window, timestamp); } - - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_WEST], - window_border.left - border.left, y, - border.left, h); - - gdk_window_move_resize (priv->border_window[GDK_WINDOW_EDGE_EAST], - window_border.left + width, y, - border.right, h); - - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_WEST]); - gdk_window_show_unraised (priv->border_window[GDK_WINDOW_EDGE_EAST]); +#endif + if (!startup_id_is_fake (priv->startup_id)) + gdk_window_set_startup_id (gdk_window, priv->startup_id); } - else + +#ifdef GDK_WINDOWING_X11 + if (priv->initial_timestamp != GDK_CURRENT_TIME) { - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_WEST]); - gdk_window_hide (priv->border_window[GDK_WINDOW_EDGE_EAST]); + if (GDK_IS_X11_WINDOW (gdk_window)) + gdk_x11_window_set_user_time (gdk_window, priv->initial_timestamp); } +#endif -shape: - /* we also update the input shape, which makes it so that clicks - * outside the border windows go through - */ + child_allocation.x = 0; + child_allocation.y = 0; + child_allocation.width = allocation.width; + child_allocation.height = allocation.height; - if (priv->type != GTK_WINDOW_POPUP) - subtract_borders (&window_border, &border); + get_shadow_width (widget, &window_border); - rect.x = window_border.left; - rect.y = window_border.top; - rect.width = gtk_widget_get_allocated_width (widget) - window_border.left - window_border.right; - rect.height = gtk_widget_get_allocated_height (widget) - window_border.top - window_border.bottom; - region = cairo_region_create_rectangle (&rect); - gtk_widget_input_shape_combine_region (widget, region); - cairo_region_destroy (region); -} + update_realized_window_properties (window, &child_allocation, &window_border); -static void -update_shadow_width (GtkWindow *window, - GtkBorder *border) -{ - GdkWindow *gdk_window; + if (priv->application) + gtk_application_handle_window_realize (priv->application, window); - gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + /* Icons */ + gtk_window_realize_icon (window); - if (gdk_window) - gdk_window_set_shadow_width (gdk_window, - border->left, - border->right, - border->top, - border->bottom); + link = priv->popovers; + + while (link) + { + GtkWindowPopover *popover = link->data; + link = link->next; + popover_realize (popover->widget, popover, window); + } + + check_scale_changed (window); } static void -corner_rect (cairo_rectangle_int_t *rect, - const GtkCssValue *value) +popover_unrealize (GtkWidget *widget, + GtkWindowPopover *popover, + GtkWindow *window) { - rect->width = _gtk_css_corner_value_get_x (value, 100); - rect->height = _gtk_css_corner_value_get_y (value, 100); + gtk_widget_unregister_window (GTK_WIDGET (window), popover->window); + gtk_widget_unrealize (popover->widget); + gdk_window_destroy (popover->window); + popover->window = NULL; } static void -subtract_corners_from_region (cairo_region_t *region, - cairo_rectangle_int_t *extents, - GtkStyleContext *context) +gtk_window_unrealize (GtkWidget *widget) { - cairo_rectangle_int_t rect; + GtkWindow *window = GTK_WINDOW (widget); + GtkWindowPrivate *priv = window->priv; + GtkWindowGeometryInfo *info; + GList *link; + gint i; - gtk_style_context_save (context); - add_window_frame_style_class (context); + /* On unrealize, we reset the size of the window such + * that we will re-apply the default sizing stuff + * next time we show the window. + * + * Default positioning is reset on unmap, instead of unrealize. + */ + priv->need_default_size = TRUE; + info = gtk_window_get_geometry_info (window, FALSE); + if (info) + { + info->resize_width = -1; + info->resize_height = -1; + info->last.configure_request.x = 0; + info->last.configure_request.y = 0; + info->last.configure_request.width = -1; + info->last.configure_request.height = -1; + /* be sure we reset geom hints on re-realize */ + info->last.flags = 0; + } - corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_LEFT_RADIUS)); - rect.x = extents->x; - rect.y = extents->y; - cairo_region_subtract_rectangle (region, &rect); + if (priv->popup_menu) + { + gtk_widget_destroy (priv->popup_menu); + priv->popup_menu = NULL; + } - corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_TOP_RIGHT_RADIUS)); - rect.x = extents->x + extents->width - rect.width; - rect.y = extents->y; - cairo_region_subtract_rectangle (region, &rect); + /* Icons */ + gtk_window_unrealize_icon (window); - corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_LEFT_RADIUS)); - rect.x = extents->x; - rect.y = extents->y + extents->height - rect.height; - cairo_region_subtract_rectangle (region, &rect); + if (priv->border_window[0] != NULL) + { + for (i = 0; i < 8; i++) + { + gtk_widget_unregister_window (widget, priv->border_window[i]); + gdk_window_destroy (priv->border_window[i]); + priv->border_window[i] = NULL; + } + } - corner_rect (&rect, _gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BORDER_BOTTOM_RIGHT_RADIUS)); - rect.x = extents->x + extents->width - rect.width; - rect.y = extents->y + extents->height - rect.height; - cairo_region_subtract_rectangle (region, &rect); + link = priv->popovers; - gtk_style_context_restore (context); + while (link) + { + GtkWindowPopover *popover = link->data; + link = link->next; + popover_unrealize (popover->widget, popover, window); + } + + GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget); + + priv->hardcoded_window = NULL; } static void -update_opaque_region (GtkWindow *window, - GtkBorder *border, - const GtkAllocation *allocation) +update_window_style_classes (GtkWindow *window) { - GtkWidget *widget = GTK_WIDGET (window); - cairo_region_t *opaque_region; + GtkWindowPrivate *priv = window->priv; GtkStyleContext *context; - gboolean is_opaque = FALSE; - - if (!gtk_widget_get_realized (widget)) - return; - - context = gtk_widget_get_style_context (widget); - - if (!gtk_widget_get_app_paintable (widget)) - { - const GdkRGBA *color; - color = _gtk_css_rgba_value_get_rgba (_gtk_style_context_peek_property (context, GTK_CSS_PROPERTY_BACKGROUND_COLOR)); - is_opaque = (color->alpha >= 1.0); - } - - if (is_opaque) - { - cairo_rectangle_int_t rect; - - rect.x = border->left; - rect.y = border->top; - rect.width = allocation->width - border->left - border->right; - rect.height = allocation->height - border->top - border->bottom; - opaque_region = cairo_region_create_rectangle (&rect); + context = gtk_widget_get_style_context (GTK_WIDGET (window)); - subtract_corners_from_region (opaque_region, &rect, context); - } + if (priv->tiled) + gtk_style_context_add_class (context, "tiled"); else - { - opaque_region = NULL; - } - - gdk_window_set_opaque_region (gtk_widget_get_window (widget), opaque_region); + gtk_style_context_remove_class (context, "tiled"); - cairo_region_destroy (opaque_region); + if (priv->maximized) + gtk_style_context_add_class (context, "maximized"); + else + gtk_style_context_remove_class (context, "maximized"); } static void @@ -7139,20 +7166,17 @@ _gtk_window_set_allocation (GtkWindow *window, gtk_widget_set_allocation (widget, allocation); - get_shadow_width (widget, &window_border); - border_width = gtk_container_get_border_width (GTK_CONTAINER (window)); - child_allocation.x = 0; child_allocation.y = 0; child_allocation.width = allocation->width; child_allocation.height = allocation->height; - priv->title_height = 0; + get_shadow_width (widget, &window_border); - if (priv->client_decorated) - update_shadow_width (window, &window_border); + if (gtk_widget_get_realized (widget)) + update_realized_window_properties (window, &child_allocation, &window_border); - update_opaque_region (window, &window_border, &child_allocation); + priv->title_height = 0; if (priv->title_box != NULL && gtk_widget_get_visible (priv->title_box) && @@ -7188,23 +7212,14 @@ _gtk_window_set_allocation (GtkWindow *window, priv->title_height; } - if (gtk_widget_get_realized (widget)) + if (!gtk_widget_is_toplevel (widget) && gtk_widget_get_realized (widget)) { - /* If it's not a toplevel we're embedded, we need to resize - * the window's window and skip the grip. - */ - if (!gtk_widget_is_toplevel (widget)) - { - gdk_window_move_resize (gtk_widget_get_window (widget), - allocation->x, allocation->y, - allocation->width, allocation->height); - } - else - { - update_border_windows (window); - } + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, allocation->y, + allocation->width, allocation->height); } + border_width = gtk_container_get_border_width (GTK_CONTAINER (window)); child_allocation.x += border_width; child_allocation.y += border_width; child_allocation.width = MAX (1, child_allocation.width - border_width * 2); -- 2.30.2